/* Sentinel - IRC Statistical and Operator Services
** split-data.c - Split service's backend functions
**
** Copyright W. Campbell and others.  See README for more details
** Some code Copyright: Jonathan George, Kai Seidler, ircd-hybrid Team,
**                      IRCnet IRCD developers.
**
** $Id: split-data.c 7 2010-02-01 19:17:42Z dubkat $
*/

#include "config.h"
#include "stats.h"
#include "struct.h"
#include "proto.h"
#include "slog.h"
#include "mem.h"

#ifdef SPLITSERV

void SpInitTables()
{
  server_table.head = NULL;
  server_table.tail = NULL;
  split_table.head = NULL;
  split_table.tail = NULL;
}

struct SpServer* SpNewServer(char* name, char* uplink)
{
  struct SpServer* up = SpFindServer(uplink);
  struct SpServer* s = smalloc(sizeof(struct SpServer));
  dlink_node *dl;
  dlink_node *dupl;

  memcounts.spserver++;
  strlcpy(s->name, name, MAXHOST);
  /* No need to zero out the leaf list, smalloc() memsets */
  s->uplink = up;
  if (up)
  {
    up->numleaf++;
    dupl = dlink_create();
    dlink_add_tail(s, dupl, &up->leaflist);
  }
  else
  {
    if (uplink != NULL) /* me... uplink will be NULL */
      slog(DEFAULT_LOG, L_ERR, "SPLIT WARNING: Unable to find uplink: %s for "
           "server name: %s", uplink, name);
  }
  dl = dlink_create();
  dlink_add_tail(s, dl, &server_table);
  return s;
}

void SpDelServer(char* name)
{
  struct SpServer* s = NULL;
  dlink_node *dl;
  dlink_node *dupl;
  struct SpServer *sup;

  if (name != NULL)
  {
    DLINK_FOREACH(dl, server_table.head)
    {
      s = (struct SpServer *) dl->data;
      if (!strcasecmp(s->name, name))
      {
        dlink_delete(dl, &server_table);
        dlink_free(dl);
        break;
      }
      /* Safe for glibc */
    }
    if (s)
    {
      if (s->uplink)
      {
        s->uplink->numleaf--;

        DLINK_FOREACH(dupl, s->uplink->leaflist.head)
        {
          sup = (struct SpServer *) dupl->data;
          if (!strcasecmp(sup->name, name))
          {
            dlink_delete(dupl,
                         &s->uplink->leaflist);
            dlink_free(dupl);
            break;
          }
          /* safe for glibc */
        }
      }

      free(s);
      memcounts.spserver--;
    }
    else
    {
      slog(DEFAULT_LOG, L_ERR, "SPLIT: No server table entry for server name: "
           "%s", name);
    }
  }
}

struct SpServer* SpFindServer(char* name)
{
  dlink_node *dl;
  struct SpServer *s;

  if (name)
  {
    DLINK_FOREACH(dl, server_table.head)
    {
      s = (struct SpServer *) dl->data;
      if (!strcasecmp(s->name, name))
      {
        return s;
      }
    }
  }
  debug("SPLIT: Unable to FindServer for name: %s", name);
  return NULL;
}

void SpNewSplit(char * name)
{
  struct SpServer* s;
  struct SpServer *t = SpFindSplit(name);
  dlink_node *dl;
  if (t)
  {
    slog(DEFAULT_LOG, L_ERR, "SPLIT: Split entry for server name: %s already "
         "exists", name);
    return ;
  }
  s = smalloc(sizeof(struct SpServer));
  memcounts.spserver++;
  dl = dlink_create();
  strlcpy(s->name, name, MAXHOST);
  s->ts = CurrentTime;
  /* None of the other variables are used here */
  dlink_add_tail(s, dl, &split_table);
}

void SpDelSplit(char * name)
{
  struct SpServer *s;
  dlink_node *dl;

  DLINK_FOREACH(dl, split_table.head)
  {
    s = (struct SpServer *) dl->data;
    if (!strcasecmp(s->name, name))
    {
      dlink_delete(dl, &split_table);
      free(s);
      memcounts.spserver--;
      dlink_free(dl);
      return ;
    }
  }
  /* New servers will get logged if logging is done here, too much
  ** useless clutter in the log file
  */
}

struct SpServer* SpFindSplit(char* name)
{
  dlink_node *dl;
  struct SpServer *spl;

  if (name)
  {
    DLINK_FOREACH(dl, split_table.head)
    {
      spl = (struct SpServer *) dl->data;
      if (!strcasecmp(spl->name, name))
      {
        return spl;
      }
    }
  }
  debug("SPLIT: Unable to FindSplit server name: %s", name);
  return NULL;
}

#endif
